package com.zhoug.player3.exo;

import android.util.Log;


import java.io.IOException;
import java.util.List;
import java.util.Map;

import androidx.annotation.Nullable;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.Format;
import androidx.media3.common.VideoSize;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.DecoderCounters;
import androidx.media3.exoplayer.DecoderReuseEvaluation;
import androidx.media3.exoplayer.analytics.AnalyticsListener;
import androidx.media3.exoplayer.source.LoadEventInfo;
import androidx.media3.exoplayer.source.MediaLoadData;

/**
 * @Author: zhoug
 * @Date: 2023/1/6
 * @Description:
 */
@UnstableApi
class ExoPlayerAnalyticsListenerWrapper implements AnalyticsListener {
    private static final String TAG = ">>>AnalyticsListener";
    private static boolean DEBUG = BuildConfig.DEBUG;




    /**
     * 当媒体源开始加载数据时调用
     *
     * @param eventTime
     * @param loadEventInfo
     * @param mediaLoadData
     */
    @Override
    public void onLoadStarted(EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
        if (DEBUG) {
            Log.d(TAG, "onLoadStarted:媒体源开始加载数据,"+loadEventInfoToString(loadEventInfo));
        }
    }

    /**
     * 当媒体源完成加载数据时调用
     *
     * @param eventTime
     * @param loadEventInfo
     * @param mediaLoadData
     */
    @Override
    public void onLoadCompleted(EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
        if (DEBUG) {
            Log.d(TAG, "onLoadCompleted:媒体源完成加载数据," +loadEventInfoToString(loadEventInfo));

        }
    }


    /**
     * 当媒体源取消加载数据时调用
     *
     * @param eventTime
     * @param loadEventInfo
     * @param mediaLoadData
     */
    @Override
    public void onLoadCanceled(EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
        if (DEBUG) {
            Log.d(TAG, "onLoadCanceled:媒体源取消加载数据,"+loadEventInfoToString(loadEventInfo));
        }
    }

    /**
     * 发生媒体源加载错误时调用
     *
     * @param eventTime
     * @param loadEventInfo
     * @param mediaLoadData
     * @param error
     * @param wasCanceled
     */
    @Override
    public void onLoadError(EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData, IOException error, boolean wasCanceled) {
        if (DEBUG) {
            Log.e(TAG, "onLoadError:媒体源加载错误,"+loadEventInfoToString(loadEventInfo));
        }
    }

    /**
     * 当发送到渲染器的下游格式更改时调用
     *
     * @param eventTime
     * @param mediaLoadData
     */
    @Override
    public void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData) {
        if (DEBUG) {
            Log.d(TAG, "onDownstreamFormatChanged:发送到渲染器的下游格式更改");
        }
    }

    /**
     * 当数据从媒体缓冲区的背面移除时调用，通常这样可以以不同的格式重新缓冲数据
     *
     * @param eventTime
     * @param mediaLoadData
     */
    @Override
    public void onUpstreamDiscarded(EventTime eventTime, MediaLoadData mediaLoadData) {
        if (DEBUG) {
            Log.d(TAG, "onUpstreamDiscarded:数据从媒体缓冲区的背面移除");
        }
    }

    /**
     * 当当前数据源的带宽估计值已更新时调用
     *
     * @param eventTime
     * @param totalLoadTimeMs
     * @param totalBytesLoaded
     * @param bitrateEstimate
     */
    @Override
    public void onBandwidthEstimate(EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) {
        if (DEBUG) {
            Log.d(TAG, "onBandwidthEstimate:当前数据源的带宽估计值已更新");
        }
    }

    /**
     * 启用音频渲染器时调用
     *
     * @param eventTime
     * @param decoderCounters
     */
    @Override
    public void onAudioEnabled(EventTime eventTime, DecoderCounters decoderCounters) {
        if (DEBUG) {
            Log.d(TAG, "onAudioEnabled:启用音频渲染器");
        }
    }

    /**
     * 当音频渲染器创建解码器时调用
     *
     * @param eventTime
     * @param decoderName
     * @param initializedTimestampMs
     * @param initializationDurationMs
     */
    @Override
    public void onAudioDecoderInitialized(EventTime eventTime, String decoderName, long initializedTimestampMs, long initializationDurationMs) {
        if (DEBUG) {
            Log.d(TAG, "onAudioDecoderInitialized:音频渲染器创建解码器");
        }
    }

    /**
     * 当音频渲染器使用的媒体格式更改时调用。
     *
     * @param eventTime
     * @param format
     * @param decoderReuseEvaluation
     */
    @Override
    public void onAudioInputFormatChanged(EventTime eventTime, Format format, @Nullable DecoderReuseEvaluation decoderReuseEvaluation) {
        if (DEBUG) {
            Log.d(TAG, "onAudioInputFormatChanged:音频渲染器使用的媒体格式更改,format" + format);
        }
    }

    /**
     * 当音频位置自上次暂停或位置重置后首次增加时调用
     *
     * @param eventTime
     * @param playoutStartSystemTimeMs
     */
    @Override
    public void onAudioPositionAdvancing(EventTime eventTime, long playoutStartSystemTimeMs) {
        if (DEBUG) {
            Log.d(TAG, "onAudioPositionAdvancing:音频位置自上次暂停或位置重置后首次增加");
        }
    }

    /**
     * 发生音频不足时调用
     *
     * @param eventTime
     * @param bufferSize
     * @param bufferSizeMs
     * @param elapsedSinceLastFeedMs
     */
    @Override
    public void onAudioUnderrun(EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {
        if (DEBUG) {
            Log.d(TAG, "onAudioUnderrun:音频不足");
        }
    }

    /**
     * 当音频渲染器释放解码器时调用
     *
     * @param eventTime
     * @param decoderName
     */
    @Override
    public void onAudioDecoderReleased(EventTime eventTime, String decoderName) {
        if (DEBUG) {
            Log.d(TAG, "onAudioDecoderReleased:音频渲染器释放解码器");
        }
    }

    /**
     * 禁用音频渲染器时调用
     *
     * @param eventTime
     * @param decoderCounters
     */
    @Override
    public void onAudioDisabled(EventTime eventTime, DecoderCounters decoderCounters) {
        if (DEBUG) {
            Log.d(TAG, "onAudioDisabled:禁用音频渲染器");
        }
    }

    /**
     * 当音频会话ID更改时调用
     *
     * @param eventTime
     * @param audioSessionId
     */
    @Override
    public void onAudioSessionIdChanged(EventTime eventTime, int audioSessionId) {
        if (DEBUG) {
            Log.d(TAG, "onAudioSessionIdChanged:音频会话ID更改,audioSessionId=" + audioSessionId);
        }
    }

    /**
     * 当音频属性更改时调用
     *
     * @param eventTime
     * @param audioAttributes
     */
    @Override
    public void onAudioAttributesChanged(EventTime eventTime, AudioAttributes audioAttributes) {
        if (DEBUG) {
            Log.d(TAG, "onAudioAttributesChanged:音频属性更改");
        }
    }

    /**
     * ｛@link AudioSink｝遇到错误时调用
     *
     * @param eventTime
     * @param audioSinkError
     */
    @Override
    public void onAudioSinkError(EventTime eventTime, Exception audioSinkError) {
        if (DEBUG) {
            Log.e(TAG, "onAudioSinkError:AudioSink遇到错误");
        }
    }

    /**
     * 当音频解码器遇到错误时调用
     *
     * @param eventTime
     * @param audioCodecError
     */
    @Override
    public void onAudioCodecError(EventTime eventTime, Exception audioCodecError) {
        if (DEBUG) {
            Log.e(TAG, "onAudioCodecError:音频解码器遇到错误");
        }
    }

    /**
     * 启用视频渲染器时调用
     *
     * @param eventTime
     * @param decoderCounters
     */
    @Override
    public void onVideoEnabled(EventTime eventTime, DecoderCounters decoderCounters) {
        if (DEBUG) {
            Log.d(TAG, "onVideoEnabled:启用视频渲染器");
        }
    }

    /**
     * 当视频渲染器创建解码器时调用
     *
     * @param eventTime
     * @param decoderName
     * @param initializedTimestampMs
     * @param initializationDurationMs
     */
    @Override
    public void onVideoDecoderInitialized(EventTime eventTime, String decoderName, long initializedTimestampMs, long initializationDurationMs) {
        if (DEBUG) {
            Log.d(TAG, "onVideoDecoderInitialized:视频渲染器创建解码器");
        }
    }

    /**
     * 当视频渲染器使用的媒体的格式更改时调用
     *
     * @param eventTime
     * @param format
     * @param decoderReuseEvaluation
     */
    @Override
    public void onVideoInputFormatChanged(EventTime eventTime, Format format, @Nullable DecoderReuseEvaluation decoderReuseEvaluation) {
        if (DEBUG) {
            Log.d(TAG, "onVideoInputFormatChanged:视频渲染器使用的媒体的格式更改,format=" + format);
        }
    }

    /**
     * 在删除视频帧后调用
     *
     * @param eventTime
     * @param droppedFrames
     * @param elapsedMs
     */
    @Override
    public void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs) {
        if (DEBUG) {
            Log.d(TAG, "onDroppedVideoFrames:删除视频帧");
        }
    }

    /**
     * 当视频渲染器释放解码器时调用
     *
     * @param eventTime
     * @param decoderName
     */
    @Override
    public void onVideoDecoderReleased(EventTime eventTime, String decoderName) {
        if (DEBUG) {
            Log.d(TAG, "onVideoDecoderReleased:视频渲染器释放解码器");
        }
    }

    /**
     * 在禁用视频渲染器时调用
     *
     * @param eventTime
     * @param decoderCounters
     */
    @Override
    public void onVideoDisabled(EventTime eventTime, DecoderCounters decoderCounters) {
        if (DEBUG) {
            Log.d(TAG, "onVideoDisabled:禁用视频渲染器");
        }
    }

    /**
     * 当视频渲染器报告的视频帧处理偏移量有更新时调用
     *
     * @param eventTime
     * @param totalProcessingOffsetUs
     * @param frameCount
     */
    @Override
    public void onVideoFrameProcessingOffset(EventTime eventTime, long totalProcessingOffsetUs, int frameCount) {
        if (DEBUG) {
            Log.d(TAG, "onVideoFrameProcessingOffset:视频渲染器报告的视频帧处理偏移量有更新");
        }
    }

    /**
     * 当视频解码器遇到错误时调用
     *
     * @param eventTime
     * @param videoCodecError
     */
    @Override
    public void onVideoCodecError(EventTime eventTime, Exception videoCodecError) {
        if (DEBUG) {
            Log.e(TAG, "onVideoCodecError:视频解码器遇到错误");
        }
    }

    /**
     * 在设置曲面后首次渲染帧时调用，或者在重置渲染器后调用，或者当正在渲染的流更改时调用
     *
     * @param eventTime
     * @param output
     * @param renderTimeMs
     */
    @Override
    public void onRenderedFirstFrame(EventTime eventTime, Object output, long renderTimeMs) {
        if (DEBUG) {
            Log.d(TAG, "onRenderedFirstFrame:在设置曲面后首次渲染帧时调用，或者在重置渲染器后调用，或者当正在渲染的流更改时调用");
        }
    }

    /**
     * 在设置曲面后首次渲染帧之前调用，并且每次渲染的视频的大小或像素纵横比发生变化时调用
     *
     * @param eventTime
     * @param videoSize
     */
    @Override
    public void onVideoSizeChanged(EventTime eventTime, VideoSize videoSize) {
        if (DEBUG) {
            Log.d(TAG, "onVideoSizeChanged:渲染的视频的大小或像素纵横比发生变化,width=" + videoSize.width + ",height=" + videoSize.height);
        }
    }

    /**
     * 每次获取drm会话时调用
     *
     * @param eventTime
     * @param state
     */
    @Override
    public void onDrmSessionAcquired(EventTime eventTime, int state) {
        if (DEBUG) {
            Log.d(TAG, "onDrmSessionAcquired:获取drm会话");
        }
    }

    /**
     * 每次加载drm密钥时调用
     *
     * @param eventTime
     */
    @Override
    public void onDrmKeysLoaded(EventTime eventTime) {
        if (DEBUG) {
            Log.d(TAG, "onDrmKeysLoaded:加载drm密钥");
        }
    }

    /**
     * 发生drm错误时调用
     *
     * @param eventTime
     * @param error
     */
    @Override
    public void onDrmSessionManagerError(EventTime eventTime, Exception error) {
        if (DEBUG) {
            Log.e(TAG, "onDrmSessionManagerError:drm错误");
        }
    }

    /**
     * 每次恢复脱机drm密钥时调用
     *
     * @param eventTime
     */
    @Override
    public void onDrmKeysRestored(EventTime eventTime) {
        if (DEBUG) {
            Log.d(TAG, "onDrmKeysRestored:恢复脱机drm密钥");
        }
    }

    /**
     * 每次删除脱机drm密钥时调用
     *
     * @param eventTime
     */
    @Override
    public void onDrmKeysRemoved(EventTime eventTime) {
        if (DEBUG) {
            Log.d(TAG, "onDrmKeysRemoved:删除脱机drm密钥");
        }
    }

    /**
     * 每次释放drm会话时调用
     *
     * @param eventTime
     */
    @Override
    public void onDrmSessionReleased(EventTime eventTime) {
        if (DEBUG) {
            Log.d(TAG, "onDrmSessionReleased:释放drm会话");
        }
    }

    /**
     * 在释放｛@link Player｝时调用
     *
     * @param eventTime
     */
    @Override
    public void onPlayerReleased(EventTime eventTime) {
        if (DEBUG) {
            Log.d(TAG, "onPlayerReleased:释放Player");
        }
    }


    private static String loadEventInfoToString(LoadEventInfo loadEventInfo) {
        if (loadEventInfo != null) {
            return "uri=" + loadEventInfo.uri
                    + ",responseHeaders=" + responseHeadersToString(loadEventInfo.responseHeaders)
                    + ",bytesLoaded=" + loadEventInfo.bytesLoaded
                    + ",dataSpec=" + loadEventInfo.dataSpec
                    + ",elapsedRealtimeMs=" + loadEventInfo.elapsedRealtimeMs
                    + ",loadDurationMs=" + loadEventInfo.loadDurationMs;
        }
        return null;
    }


    /**
     * response Headers 转化成字符串
     *
     * @param responseHeaders
     * @return
     */
    private static String responseHeadersToString(Map<String, List<String>> responseHeaders) {
        if (responseHeaders != null && responseHeaders.size() > 0) {
            StringBuilder builder = new StringBuilder();
            for (String key : responseHeaders.keySet()) {
                builder.append(key);
                builder.append("=");
                String value = "";
                List<String> list = responseHeaders.get(key);
                if (list != null && list.size() > 0) {
                    for (String item : list) {
                        value += item;
                        value += ",";
                    }
                }
                if (value.length() > 0 && value.endsWith(",")) {
                    value = value.substring(0, value.length() - 1);
                }
                builder.append(value);
                builder.append(";");
            }
            return builder.toString();
        }
        return null;
    }


}
